package com.aplikata.evok.ui;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

import net.sf.jasperreports.engine.JasperPrint;

import org.hibernate.Hibernate;
import org.primefaces.event.SelectEvent;
import org.springframework.jdbc.core.JdbcTemplate;

import com.aplikata.bo.City;
import com.aplikata.bo.Employee;
import com.aplikata.bo.Node;
import com.aplikata.bo.User;
import com.aplikata.constants.Constants;
import com.aplikata.constants.ConstantsMsg;
import com.aplikata.evok.bo.ContactPerson;
import com.aplikata.evok.bo.DomainPatient;
import com.aplikata.evok.bo.Patient;
import com.aplikata.evok.bo.PatientNode;
import com.aplikata.evok.constants.EvokConstants;
import com.aplikata.evok.datamodel.ContactPersonDataModel;
import com.aplikata.evok.datamodel.PatientDataModel;
import com.aplikata.evok.service.EvokPatientService;
import com.aplikata.ui.AplikataReportUIBean;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.ReportUtil;
import com.aplikata.util.StringUtil;
import com.aplikata.util.YunDateUtil;

/**
 * @ClassName: EvokPatientBean
 * @Description: TODO
 * @author Huyun
 * @date 17. 5. 2012. 09:10:03
 */
@ManagedBean(name = "evokPatientBean")
@ViewScoped
public class EvokPatientBean extends AplikataReportUIBean {
	private static final long serialVersionUID = 1L;
	private Long roleId;

	private String qyPatientName;
	private Patient patient;
	private DomainPatient domainPatient;

	private PatientDataModel patientModel;
	private List<PatientNode> pnList;

	@ManagedProperty(value = "#{evokPatientService}")
	private EvokPatientService patientService;

	@ManagedProperty(value = "#{jdbcTemplate}")
	private JdbcTemplate jdbcTemplate;

	private boolean readonly;

	private City birthCity;
	private Long birthRegionId;
	private Long birthCityId;
	private String birthPostcode;
	private List<City> birthCityList;

	private City liveCity;
	private Long liveRegionId;
	private Long liveCityId;
	private String livePostcode;
	private List<City> liveCityList;
	private String userName;

	private ContactPerson contactPerson;
	private ContactPersonDataModel contactPersonModel;
	private Long contactRegionId;
	private Long contactCityId;
	private String contactPostcode;
	private List<City> contactCityList;

	private int tabIndex;

	@PostConstruct
	public void init() {
		patient = new Patient();
		domainPatient = new DomainPatient(YunDateUtil.getDate());
		roleId = FacesUtil.getUserFromSession().getRole().getId();
		contactPerson = new ContactPerson();
	}

	@SuppressWarnings("unchecked")
	public List<String> completeQueryName(String query) {
		return (List<String>) patientService.findByNamedQuery(Patient.QY_FINDNAME, new Object[] { query + "%" });
	}

	@SuppressWarnings("unchecked")
	public void selectPatientName(SelectEvent event) {
		FacesUtil.resetInput("mainform:pnlinfo");
		qyPatientName = (String) event.getObject();
		String idString = qyPatientName.substring(qyPatientName.lastIndexOf(" "), qyPatientName.length());
		Long id = Long.parseLong(idString.trim());
		List<Patient> list = (List<Patient>) patientService
				.findByNamedQuery(Patient.QY_FIND_BY_ID, new Object[] { id });

		if (patientModel == null) {
			patientModel = new PatientDataModel(patientService, list);
		} else {
			patientModel.setWrappedData(list);
		}

		selectPatient(list.get(0));
		FacesUtil.unselectTableRows("wdgPatientList");
	}

	@SuppressWarnings({})
	public void selectPatient(SelectEvent event) {
		FacesUtil.resetInput("mainform:pnlinfo");
		selectPatient((Patient) event.getObject());
	}

	@SuppressWarnings("rawtypes")
	private void selectPatient(Patient pt) {
		patient = pt;

		String sqlcity = "select {c1.*}, d.id as domainId from evk_patient p, _city c1, _user u, _domain d where c1.id = p.birthplace and p.id = "
				+ patient.getId() + " and p.oper_id = u.id and u.domain_id = d.id";
		List listcity = patientService.getSqlQuery(sqlcity).addEntity("c1", City.class)
				.addScalar("domainId", Hibernate.LONG).list();
		Object[] obj = (Object[]) listcity.get(0);
		birthCity = (City) obj[0];
		birthRegionId = birthCity == null ? null : birthCity.getRegion().getId();
		birthRegionChange();
		birthCityId = birthCity == null ? null : birthCity.getId();
		birthPostcode = birthCity == null ? null : birthCity.getPostCode();

		Long domainId = (Long) obj[1];
		if (getQyDomainId().equals(domainId)) {
			readonly = false;
		} else {
			readonly = true;
		}

		domainPatient = (DomainPatient) patientService.findSingleByNamedQuery(DomainPatient.QY_FIND_DOMAIN_PATIENT,
				new Object[] { getQyDomainId(), patient.getId() });
		if (domainPatient == null) {
			domainPatient = new DomainPatient(YunDateUtil.getDate());
			pnList = null;
		} else {
			sqlcity = "select {c1.*} from evk_domain_patient p, _city c1, _user u, _domain d where c1.id = p.city_id and p.id = "
					+ domainPatient.getId();
			listcity = (List) patientService.getSqlQuery(sqlcity).addEntity("c1", City.class).list();
			liveCity = null;
			liveRegionId = null;
			liveCityId = null;
			livePostcode = null;
			
			if (listcity != null && !listcity.isEmpty()) {
				liveCity = (City) listcity.get(0);

				if (liveCity != null) {
					liveRegionId = liveCity.getRegion().getId();
					liveRegionChange();
					liveCityId = liveCity.getId();
					livePostcode = liveCity.getPostCode();
				}
			}
			String sql = "SELECT {epn.*}, {p.*} FROM (select n.* from _access a, _node n  " + " where a.role_id = "
					+ roleId + " and a.node_id = n.id and n.type = " + EvokConstants.NODE_TYPE_PATIENT_BASIC + ") p "
					+ " left join evk_patient_node epn on p.id = epn.node_id and epn.domain_patient_id = "
					+ domainPatient.getId() + " order by p.sort";

			List list = patientService.getSqlQuery(sql).addEntity("epn", PatientNode.class).addEntity("p", Node.class)
					.list();
			if (list == null || list.isEmpty())
				return;

			pnList = new ArrayList<PatientNode>();
			for (int i = 0; i < list.size(); i++) {
				Object[] objs = (Object[]) list.get(i);
				PatientNode pn = (PatientNode) objs[0];
				Node node = (Node) objs[1];

				if (pn != null) {
					pn.setNode(node);
					pnList.add(pn);
				} else {
					pnList.add(new PatientNode(domainPatient, node));
				}
			}
		}
		addDomainPatientToFlash();
		
		contactPerson = new ContactPerson();
		contactRegionId = null;
		contactCityId = null;
		contactPersonModel = null;
		tabIndex = 0;
		userName = this.getUserName(patient);
	}

	public void addPatient() {
		FacesUtil.resetInput("mainform:paitentInfo");
		tabIndex = 0;
		qyPatientName = null;
		patient = new Patient();
		domainPatient = new DomainPatient();
		birthRegionId = null;
		birthCityId = null;
		birthPostcode = null;
		liveRegionId = null;
		liveCityId = null;
		livePostcode = null;
		patientModel.setWrappedData(new ArrayList<Patient>());
		userName = null;
		readonly = false;
		FacesUtil.unselectTableRows("wdgPatientList");
	}

	public void submitPatient() {
		try {
			Long tempId = patient.getId();

			if (birthCityId != null) {
				patient.setBirthplace((City) patientService.get(City.class, birthCityId));
			}
			if (liveCityId != null) {
				domainPatient.setCity((City) patientService.get(City.class, liveCityId));
			}

			userName = this.getUserName();
			domainPatient = patientService.updatePatient(readonly, patient, domainPatient, userName, pnList);
			patient = domainPatient.getPatient();
			FacesUtil.addInfoMessage(ConstantsMsg.INFO_SUCCESS,
					new Object[] { patient.getSurname() + " " + patient.getName() });

			qyPatientName = patient.getSurname() + " " + patient.getName();
			List<Patient> list = new ArrayList<Patient>();
			list.add(patient);
			patientModel = new PatientDataModel(patientService, list);

			if (FacesUtil.isKeyNull(tempId)) {
				pnList = null;
				pnList = this.getPnList();
				contactPerson = new ContactPerson();
				contactPersonModel = null;
			}
			addDomainPatientToFlash();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	@SuppressWarnings("unchecked")
	public void birthRegionChange() {
		if (birthRegionId == null)
			birthCityList = null;
		else
			birthCityList = (List<City>) patientService.findByNamedQuery(City.QY_FIND_BY_REGION,
					new Object[] { birthRegionId });

		birthPostcode = null;
	}

	public void birthCityChange() {
		City city = (City) patientService.get(City.class, birthCityId);
		birthPostcode = city.getPostCode();
	}

	@SuppressWarnings("unchecked")
	public void liveRegionChange() {
		if (liveRegionId == null)
			liveCityList = null;
		else
			liveCityList = (List<City>) patientService.findByNamedQuery(City.QY_FIND_BY_REGION,
					new Object[] { liveRegionId });

		livePostcode = null;
	}

	public void liveCityChange() {
		City city = (City) patientService.get(City.class, liveCityId);
		livePostcode = city.getPostCode();
	}

	@SuppressWarnings("unchecked")
	public void contactRegionChange() {
		if (contactRegionId == null)
			contactCityList = null;
		else
			contactCityList = (List<City>) patientService.findByNamedQuery(City.QY_FIND_BY_REGION,
					new Object[] { contactRegionId });

		contactPostcode = null;
	}

	public void contactCityChange() {
		City city = (City) patientService.get(City.class, contactCityId);
		contactPostcode = city.getPostCode();
	}

	public void submitContactPerson() {
		try {
			if (domainPatient == null || FacesUtil.isKeyNull(domainPatient.getId()) || contactPerson == null)
				return;

			if (contactCityId != null) {
				contactPerson.setCity((City) patientService.get(City.class, contactCityId));
			}

			contactPerson.setDomainPatient(domainPatient);
			patientService.updatePatientContactPerson(contactPerson);
			resetContactPerson();
			contactPersonModel = null;
			contactPersonModel = this.getContactPersonModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public void resetContactPerson() {
		FacesUtil.resetInput("mainform:paitentInfo:contactPersonInfo");
		contactPerson = new ContactPerson();
		contactRegionId = null;
		contactCityId = null;
		contactPostcode = null;
		FacesUtil.unselectTableRows("wdgContactList");
	}

	public void selectContactPerson(SelectEvent event) {
		FacesUtil.resetInput("mainform:paitentInfo:contactPersonInfo");
		contactPerson = (ContactPerson) event.getObject();
		City city = contactPerson.getCity();
		contactRegionId = city == null ? null : city.getRegion().getId();
		contactRegionChange();
		contactCityId = city == null ? null : city.getId();
		contactPostcode = city == null ? null : city.getPostCode();
	}

	public void deleteContactPerson() {
		try {
			patientService.delete(contactPerson);
			contactPerson = new ContactPerson();
			contactRegionId = null;
			contactCityId = null;
			contactPostcode = null;
			contactPersonModel = null;
			contactPersonModel = this.getContactPersonModel();
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		}
	}

	public String getUserName() {
		if (!StringUtil.isStrEmpty(userName))
			return userName;

		if (patient == null)
			return null;

		if (!FacesUtil.isKeyNull(patient.getId())) {
			User user = null;
			user = (User) patientService.findSingleByNamedQuery(Patient.QY_FIND_USER, new Object[] { patient.getId() });
			userName = user == null ? null : user.getUserName();
			return userName;
		}

		String name = patient.getName();
		if (!StringUtil.isStrEmpty(name)) {
			name = name.substring(0, 1).toLowerCase();
		} else {
			name = "";
		}
		String surname = patient.getSurname();
		if (!StringUtil.isStrEmpty(surname)) {
			surname = surname.toLowerCase(Locale.ENGLISH);
			if (surname.length() > 11) {
				surname = surname.substring(0, 10);
			}
		} else {
			surname = "";
		}
		String birthday = YunDateUtil.formatDate(patient.getBirthday(), "ddMMyyyy");
		userName = name + surname + birthday;
		return userName;
	}

	private String getUserName(Patient patient) {
		if (!FacesUtil.isKeyNull(patient.getId())) {
			User user = null;
			user = (User) patientService.findSingleByNamedQuery(Patient.QY_FIND_USER, new Object[] { patient.getId() });
			userName = user == null ? null : user.getUserName();
			return userName;
		}

		return userName;
	}

	public String getQyPatientName() {
		return qyPatientName;
	}

	public void setQyPatientName(String qyPatientName) {
		this.qyPatientName = qyPatientName;
	}

	public EvokPatientService getPatientService() {
		return patientService;
	}

	public void setPatientService(EvokPatientService patientService) {
		this.patientService = patientService;
	}

	public Patient getPatient() {
		return patient;
	}

	public void setPatient(Patient patient) {
		this.patient = patient;
	}

	public PatientDataModel getPatientModel() {
		return patientModel;
	}

	public void setPatientModel(PatientDataModel patientModel) {
		this.patientModel = patientModel;
	}

	@SuppressWarnings({ "unchecked" })
	public List<PatientNode> getPnList() {
		if (pnList == null) {
			List<Node> nodelist = (List<Node>) patientService.findByNamedQuery(Node.QY_FIND_ROLE_NODES, new Object[] {
					EvokConstants.NODE_TYPE_PATIENT_BASIC, roleId });
			if (nodelist == null || nodelist.isEmpty())
				return pnList;

			pnList = new ArrayList<PatientNode>();
			for (Node node : nodelist) {
				PatientNode pn = new PatientNode(domainPatient, node);
				pnList.add(pn);
			}
		}
		return pnList;
	}

	public void setPnList(List<PatientNode> pnList) {
		this.pnList = pnList;
	}

	public Long getBirthRegionId() {
		return birthRegionId;
	}

	public void setBirthRegionId(Long birthRegionId) {
		this.birthRegionId = birthRegionId;
	}

	public Long getBirthCityId() {
		return birthCityId;
	}

	public void setBirthCityId(Long birthCityId) {
		this.birthCityId = birthCityId;
	}

	public String getBirthPostcode() {
		return birthPostcode;
	}

	public void setBirthPostcode(String birthPostcode) {
		this.birthPostcode = birthPostcode;
	}

	public List<City> getBirthCityList() {
		return birthCityList;
	}

	public void setBirthCityList(List<City> birthCityList) {
		this.birthCityList = birthCityList;
	}

	public Long getLiveRegionId() {
		return liveRegionId;
	}

	public void setLiveRegionId(Long liveRegionId) {
		this.liveRegionId = liveRegionId;
	}

	public Long getLiveCityId() {
		return liveCityId;
	}

	public void setLiveCityId(Long liveCityId) {
		this.liveCityId = liveCityId;
	}

	public String getLivePostcode() {
		return livePostcode;
	}

	public void setLivePostcode(String livePostcode) {
		this.livePostcode = livePostcode;
	}

	public List<City> getLiveCityList() {
		return liveCityList;
	}

	public void setLiveCityList(List<City> liveCityList) {
		this.liveCityList = liveCityList;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public ContactPerson getContactPerson() {
		return contactPerson;
	}

	public void setContactPerson(ContactPerson contactPerson) {
		this.contactPerson = contactPerson;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public ContactPersonDataModel getContactPersonModel() {
		if (domainPatient == null || FacesUtil.isKeyNull(domainPatient.getId()))
			return null;

		if (contactPersonModel == null) {
			List list = patientService.findByNamedQuery(ContactPerson.QY_FIND_BY_PATIENT,
					new Object[] { domainPatient.getId() });
			contactPersonModel = new ContactPersonDataModel(patientService, list);
		}
		return contactPersonModel;
	}

	public void setContactPersonModel(ContactPersonDataModel contactPersonModel) {
		this.contactPersonModel = contactPersonModel;
	}

	public Long getContactRegionId() {
		return contactRegionId;
	}

	public void setContactRegionId(Long contactRegionId) {
		this.contactRegionId = contactRegionId;
	}

	public Long getContactCityId() {
		return contactCityId;
	}

	public void setContactCityId(Long contactCityId) {
		this.contactCityId = contactCityId;
	}

	public String getContactPostcode() {
		return contactPostcode;
	}

	public void setContactPostcode(String contactPostcode) {
		this.contactPostcode = contactPostcode;
	}

	public List<City> getContactCityList() {
		return contactCityList;
	}

	public void setContactCityList(List<City> contactCityList) {
		this.contactCityList = contactCityList;
	}

	public int getTabIndex() {
		return tabIndex;
	}

	public void setTabIndex(int tabIndex) {
		this.tabIndex = tabIndex;
	}

	public void addDomainPatientToFlash() {
		FacesContext.getCurrentInstance().getExternalContext().getFlash()
				.put(EvokConstants.FLASH_DOMAIN_PATIENT, domainPatient);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void generatePdfReport(ActionEvent actionEvent) {
		if (patient == null || FacesUtil.isKeyNull(patient.getId()))
			return;

		List list = new ArrayList();
		list.add(patient);
		Connection connection = null;
		try {
			Employee emp = FacesUtil.getEmpFromSession();
			String doctorname = emp == null ? null : emp.getSurname() + " " + emp.getName();

			connection = jdbcTemplate.getDataSource().getConnection();
			List<JasperPrint> printlist = new ArrayList<JasperPrint>();
			String sql = " select c.city_name from _domain d, _city c where c.id=d.city_id and d.id = "
					+ FacesUtil.getDomainFromSession().getId();
			String sql1 = " SELECT {u.*} FROM evk_patient p, _user u where p.user_id = u.id and p.id = "
					+ patient.getId();
			User user = (User) patientService.getSqlQuery(sql1).addEntity("u", User.class).uniqueResult();

			Map map = this.getCommonMap();
			map.put("domain_city", patientService.findSingleBySql(sql));
			map.put("patient_name", patient.getSurname().toUpperCase() + " " + patient.getName().toUpperCase());
			map.put("doctor_name", doctorname);
			map.put("patient_user_name", user.getUserName());
			map.put("patient_user_password", Constants.DEFAULT_USER_PASSWORD);
			map.put("REPORT_CONNECTION", connection);
			JasperPrint print = ReportUtil.createJasperPrint("rp_patient_user", map, list);
			printlist.add(print);
			if (printlist.isEmpty())
				return;

			ReportUtil.generateReport(ReportUtil.PDF, printlist, "patientUser" + patient.getId());
		} catch (Exception e) {
			FacesUtil.addActionListenerException(e, log);
		} finally {
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					log.error(e);
				}
			}
		}
	}

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public DomainPatient getDomainPatient() {
		return domainPatient;
	}

	public void setDomainPatient(DomainPatient domainPatient) {
		this.domainPatient = domainPatient;
	}

	public City getBirthCity() {
		return birthCity;
	}

	public void setBirthCity(City birthCity) {
		this.birthCity = birthCity;
	}

	public boolean isReadonly() {
		return readonly;
	}

	public void setReadonly(boolean readonly) {
		this.readonly = readonly;
	}

	public City getLiveCity() {
		return liveCity;
	}

	public void setLiveCity(City liveCity) {
		this.liveCity = liveCity;
	}

}
